
<template>
  <div class="express-automatic-container">
    <div
      class="express-automatic"
      :class="[`express-automatic--${size}`]"
    >
      <div class="express-automatic__wrap">
        <div
          ref="inputContainer"
          v-popover:suggestions
          class="express-automatic__input"
          :class="activated?'is-focus':(showError && 'is-error')"
        >
          <div
            v-if="prefix || $slots.prefix"
            class="express-automatic__input-prefix"
          >
            <slot name="prefix">
              {{ prefix }}
            </slot>
          </div>
          <div class="express-automatic__input-input">
            <el-input
              ref="input"
              v-model="inputValue"
              v-alphanumeric
              :pattern="extraRegx"
              :size="size"
              :placeholder="placeholder"
              @input="handleInput"
              @change="handleChange"
              @focus="handleFocus"
              @blur="handleBlur"
            />
          </div>
          <div class="express-automatic__input-suffix">
            {{ checkedExpressName }}
          </div>
        </div>
        <slot name="append" />
      </div>

      <div
        v-if="showError"
        class="express-automatic__error"
      >尚未识别物流公司，请检查后重新填写{{ activeId }}</div>

    </div>
    <el-popover
      ref="suggestions"
      v-model="suggestionVisible"
      :width="popoverWidth"
      :placement="placement"
      :append-to-body="popperAppendToBody"
      trigger="manual"
      popper-class="express-automatic__popper"
      :visible-arrow="false"
    >
      <ul class="express-automatic__suggestions">
        <li
          v-for="(item, index) in suggestions"
          :key="index"
          role="option"
          @click="onSelectItem(item)"
        >
          <div :class="item.express && 'suggestions-node'">
            {{ item[suggestionValueKey] }}
          </div>
        </li>
      </ul>
      <div
        v-if="inputValue"
        class="express-automatic__manual"
      >
        <div class="express-automatic__manual-item last">
          <span class="mr-2">上次：</span>
          <div class="express-automatic__manual-item__tags">
            <el-tag
              v-if="express"
              size="mini"
              @click="onSelectCompany(express)"
            >{{ express.name }}</el-tag>
          </div>
        </div>
        <div class="express-automatic__manual-item common">
          <span class="mr-2">常用：</span>
          <div class="express-automatic__manual__tags">
            <el-tag
              v-for="(comexpress,index) in expressCommons"
              :key="index"
              type="default"
              size="mini"
              @click="onSelectCompany(comexpress)"
            >{{ comexpress.name }}</el-tag>
          </div>
        </div>
        <div class="manual">
          <span class="mr-2">未识别或识别有误请手动</span>
          <el-button
            type="text"
            :size="size"
            @click="dialogVisible = true"
          >选择物流公司</el-button>
        </div>
      </div>
    </el-popover>
    <el-dialog
      title="选择物流公司"
      :visible.sync="dialogVisible"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      class="express-automatic__picker"
      width="750px"
      lock-scroll
      append-to-body
    >
      <el-tabs v-model="activeTabname">
        <el-tab-pane
          v-for="(tab,tindex) in expressCompany"
          :key="tindex"
          :label="tab.label"
          :name="tab.name"
        >
          <el-scrollbar
            style="height:400px"
            wrap-style="overflow-x:hidden;"
          >
            <index-grid
              :items="tab.data"
              :columns="tab.columns"
              :spans="tab.spans"
              @select="onSelectCompany"
            />
          </el-scrollbar>
        </el-tab-pane>
      </el-tabs>
      <template slot="footer">
        <span>
          如列表未找到，请选择
          <el-button
            type="text"
            size="small"
            @click="onSelectCompany(other)"
          >其他物流公司</el-button>
        </span>
        <el-link>【物流公司】列表问题反馈建议</el-link>
      </template>
    </el-dialog>
  </div>
</template>
<script>
import debounce from 'throttle-debounce/debounce'
import IndexGrid from '@/components/IndexGrid'

export default {
  name: 'FormExpressInput',
  components: {
    IndexGrid
  },
  props: {
    value: {
      type: [String, Number],
      default: ''
    },
    activeId: {
      type: [String, Number],
      default: ''
    },
    hint: {
      type: String,
      default: ''
    },
    rules: {
      type: [Object, Array],
      default: null
    },
    label: {
      type: String,
      default: ''
    },
    prefix: {
      type: String,
      default: ''
    },
    extraRegx: {
      type: String,
      default: ''
    },
    prop: {
      type: String,
      default: ''
    },
    size: {
      type: String,
      default: 'small'
    },
    align: {
      type: String,
      default: 'left'
    },
    disabled: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: '请输入单号再选择物流公司'
    },
    placement: {
      type: String,
      default: 'bottom-start'
    },
    popperAppendToBody: {
      type: Boolean,
      default: true
    },
    logistics: {
      type: Array,
      default: () => {
        return []
      }
    },
    logisticsCommon: {
      type: Array,
      default: () => {
        return []
      }
    },
    logisticsRecent: {
      type: Array,
      default: () => {
        return [
          {
            abbr: 'Rfd',
            code: 'RFD',
            common: 0,
            id: 174,
            listorder: 0,
            logo: '',
            name: '如风达',
            regx: '^[\\x21-\\x7e]{1,12}$',
            telephone: '',
            thumb: null,
            type: 0
          }
        ]
      }
    },
    suggestionValueKey: {
      type: String,
      default: 'value'
    },
    triggerOnFocus: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      express: null,
      activeTabname: 'common',
      other: {
        id: 0,
        name: '其他',
        thumb: null,
        logo: '',
        common: '',
        telephone: '',
        type: 0,
        abbr: '其他',
        code: 'other',
        regx: '',
        listorder: 0
      },
      activated: false,
      popoverWidth: 300,
      suggestions: [],
      dialogVisible: false,
      loading: false,
      suggestionDisabled: false,
      checkedExpressName: ''
    }
  },
  computed: {
    expressCompany() {
      return this.groupIndex(this.logistics)
    },
    showError() {
      if (!this.inputValue || !!this.checkedExpressName) {
        return false
      } else {
        // console.log(this.inputValue)
        // console.log(this.checkedExpressName)
        // console.log(!this.inputValue || this.checkedExpressName)
        return true
      }
    },
    suggestionVisible: {
      get() {
        const suggestions = this.suggestions
        const isValidData = Array.isArray(suggestions) && suggestions.length > 0
        return (isValidData || this.loading) && this.activated
      },
      set(v) {
        console.log('suggestionVisible', v)
      }
    },
    inputValue: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit('input', val)
      }
    },
    regxLogistics() {
      return this.logistics.filter(item => {
        return item.regx
      })
    },
    expressCompanys() {
      return [...this.logistics, this.other]
    },
    activeExpress() {
      return this.expressCompanys.find(item => {
        return item.id === this.activeId
      })
    },
    expressCommons() {
      return this.logistics.filter(item => {
        return item.storeCommon
      })
    }
  },
  watch: {
    activeExpress(v) {
      this.checkedExpressName = v && v.name
    }
  },
  mounted() {
    this.$nextTick(_ => {
      this.popoverWidth = this.getInputContainer().offsetWidth
      this.checkedExpressName = this.activeExpress && this.activeExpress.name
    })
    this.debouncedGetData = debounce(this.debounce, this.getData)
    this.$on('item-click', item => {
      this.onSelectItem(item)
    })
    const $input = this.getInput()
    $input.setAttribute('role', 'textbox')
  },
  beforeDestroy() {
    this.$refs.suggestions.$destroy()
  },
  methods: {
    groupIndex(listData) {
      const tabs = [
        {
          label: '常用快递',
          name: 'common',
          common: 1,
          columns: 2,
          spans: 4,
          type: 0,
          data: []
        },
        {
          label: '货运',
          name: 'freight',
          common: 0,
          columns: 3,
          type: 10,
          data: []
        },
        {
          label: '国际发货',
          name: 'international',
          common: 0,
          type: 20,
          columns: 3,
          data: []
        },
        {
          label: '其他',
          name: 'other',
          common: 0,
          type: 0,
          columns: 3,
          data: []
        }
      ]
      var tabSize = tabs.length
      for (let i = 0; i < listData.length; i++) {
        var item = listData[i]
        for (let j = 0; j < tabSize; j++) {
          var tab = tabs[j]
          if (tab.common && tab.common === item.common) {
            tabs[j].data.push(item)
            break
          } else if (!tab.common && tab.type === item.type) {
            tabs[j].data.push(item)
            break
          }
        }
      }
      return tabs
    },
    getMigratingConfig() {
      return {
        props: {
          'custom-item': 'custom-item is removed, use scoped slot instead.',
          props: 'props is removed, use value-key instead.'
        }
      }
    },
    getData(queryString) {
      if (this.suggestionDisabled) {
        return
      }
      this.loading = true
      this.fetchSuggestions(queryString, suggestions => {
        this.loading = false
        if (this.suggestionDisabled) {
          return
        }
        if (Array.isArray(suggestions)) {
          this.suggestions = suggestions
        } else {
          console.error('[Element Error][Autocomplete]autocomplete suggestions must be an array')
        }
      })
    },
    handleInput(value) {
      this.$emit('input', value)
      this.suggestionDisabled = false
      this.checkedExpressName = ''
      if (!this.triggerOnFocus && !value) {
        this.suggestionDisabled = true
        this.suggestions = []
        return
      }
      this.debouncedGetData(value)
    },
    handleChange(value) {
      this.$emit('change', value)
    },
    handleFocus(event) {
      this.activated = true
      this.$emit('focus', event)
      if (this.triggerOnFocus) {
        this.debouncedGetData(this.value)
      }
    },
    handleBlur(event) {
      this.activated = false
      this.$emit('blur', event)
    },
    onSelectCompany(item) {
      console.log('onSelectCompany', item)
      this.checkedExpressName = item.name
      this.express = item
      this.dialogVisible = false
      this.$emit('express', item)
      this.$nextTick(_ => {
        this.suggestions = []
        if (!this.inputValue) {
          this.checkedExpressName = ''
        }
      })
    },
    onSelectItem(item) {
      const { express } = item
      this.onSelectCompany(express)
    },
    getInput() {
      return this.$refs.input.getInput()
    },
    getInputContainer() {
      return this.$refs.inputContainer
    },
    fetchSuggestions(queryString, cb) {
      var results = []
      if (queryString) {
        var matches = this.regxLogistics.filter(item => {
          var regx = new RegExp(item.regx)
          return regx.test(queryString)
        })
        if (matches.length > 0) {
          results = matches.map(item => {
            return {
              value: item.name,
              express: item
            }
          })
        } else {
          results.push({
            value: '未识别物流公司...',
            express: null
          })
        }
      } else {
        results.push({
          value: '待输入...',
          express: null
        })
      }
      // 调用 callback 返回建议列表的数据
      cb(results)
    },
    handleSelect(data) {
      if (data.express) {
        this.checkedExpressName = data.express.name
      }
    },
    createFilter(queryString) {
      return restaurant => {
        return restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
      }
    }
  }
}
</script>

<style lang="scss">
.express-automatic {
  $last-rule: &;
  display: inline-block;
  width: 100%;
  &--mini {
    font-size: 12px;
  }
  &--small {
    font-size: 13px;
    .el-input {
      &__inner {
        height: 30px;
        line-height: 30px;
      }
    }
    #{$last-rule}__input {
      line-height: 30px;
    }
  }
  &--medium {
    font-size: 14px;
    .el-input {
      &__inner {
        height: 30px;
        line-height: 30px;
      }
    }
  }
  &__wrap {
    display: flex;
    align-items: center;
  }
  &__input {
    display: flex;
    width: 100%;
    align-items: center;
    background-color: #fff;
    border-radius: 4px;
    border: 1px solid #dcdfe6;
    position: relative;
    &:hover {
      border-color: #c0c4cc;
    }
    &.is-focus {
      border-color: #1890ff;
    }
    &.is-required,
    &.is-error {
      border-color: #ff4949;
    }

    &-prefix {
      padding-left: 15px;
    }
    &-suffix {
      padding-right: 15px;
      color: #b0b0b0;
    }
    &-input {
      flex: 1;
    }
    .el-input {
      &__inner {
        border: none;
        background-color: transparent;
      }
    }
    & + * {
      margin-left: 10px;
    }
  }
  &__popper {
    padding: 0;
    &.el-popper[x-placement^='bottom'] {
      margin: 2px 0 0;
    }
    &.el-popper[x-placement^='top'] {
      margin: 0 0 2px;
    }
    #{$last-rule}__suggestions {
      margin: 0;
      padding: 5px 0;
      li {
        margin: 0;
        line-height: 34px;
        color: #666;
        font-size: 14px;
        list-style: none;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        > * {
          padding: 0 15px;
        }
        .suggestions-node {
          cursor: pointer;
        }
        &:hover {
          .suggestions-node {
            background-color: #f5f7fa;
          }
        }
      }
    }
  }
  &__manual {
    border-top: 1px solid #e6ebf5;
    padding: 6px 15px;
    font-size: 12px;
    > * {
      line-height: 30px;
      display: flex;
      align-items: center;
    }
    .el-tag {
      cursor: pointer;
    }
    &-item {
      > span {
        flex: none;
      }
      &__tags {
        display: inline-flex;
        align-items: center;
        flex-wrap: wrap;
      }
    }
  }

  &__error {
    color: #ff4949;
    font-size: 12px;
    line-height: 1;
    padding: 4px 0 0 2px;
  }
  &__picker {
    .el-dialog__body {
      padding: 0 20px;
    }
    .el-dialog__footer {
      border-top: 1px solid #e6ebf5;
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px 20px;
    }
  }
}
</style>
